﻿#region License Info
//Component of Cronos Package, http://www.codeplex.com/cronos
//Copyright (C) 2009 Anthony Brockwell

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#endregion


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using ExtraControlLibrary.Forms;
using MathNet.Numerics.LinearAlgebra;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Pdf;

namespace ExtraControlLibrary
{
    public partial class ACFPlotBox : BarPlotBox
    {
        public Vector ACF { get; protected set; }
        public int NumObs { get; protected set; }
        public int[] Lags { get; protected set; }

        public bool ShowLag0 { get; set; }

        public ACFPlotBox()
        {
            InitializeComponent();
        }

        protected override void AfterLabelsBeforeBars(object graphicsObject)
        {
            if (NumObs == 0)
                return;  // no bars

            var g = graphicsObject as Graphics;
            var xg = graphicsObject as XGraphics;

            double rx = 1.96/Math.Sqrt(NumObs);

            int y0 = MaptoYPixel(-rx);
            if (y0 >= GraphRectangle.Bottom)
                y0 = GraphRectangle.Bottom-1;
            int y1 = MaptoYPixel(rx);
            if (y1 < GraphRectangle.Top+1)
                y1 = GraphRectangle.Top+1;

            var rect = new Rectangle(GraphRectangle.Left + 1, y1, GraphRectangle.Width - 2, (y0 - y1 + 1));
            if (g != null)
                g.FillRectangle(Brushes.LightBlue, rect);
            if (xg != null)
                xg.DrawRectangle(Brushes.LightBlue, rect);
        }

        protected virtual void SetBars(Matrix bars, int originalN)
        {
            NumObs = originalN;
            this.bars = bars;
            ScanForLimits();

            // now make some adjustments for an ACF plot
            xunits = 1.0;
            yunits = 0.1;

            leftX = bars[0, 0];
            rightX = bars[bars.RowCount - 1, 0];
        }

        public void SetACF(int[] lags, Vector acf, int nobs)
        {
            double minVal = double.MaxValue;
            double maxVal = double.MinValue;
            var barInfo = new List<Vector>(acf.Length+1);
            for (int i = 0; i < acf.Length; ++i)
            {
                if (lags[i] != 0 || ShowLag0)
                {
                    var v = new Vector(new[] {lags[i], acf[i], 0.15});
                    barInfo.Add(v);
                    if (acf[i] > maxVal)
                        maxVal = acf[i];
                    if (acf[i] < minVal)
                        minVal = acf[i];
                }
            }

            var testm = new Matrix(barInfo.Count, 3);
            for (int i = 0; i < barInfo.Count; ++i)
                for (int j = 0; j < 3; ++j)
                    testm[i, j] = barInfo[i][j];

            SetBars(testm, nobs);

            // now override the limits obtained in ScanForLimits (from within SetBars)
            if (ShowLag0 || minVal == maxVal)
            {
                bottomY = -1.0;
                topY = 1.0;
                yunits = 0.2;
            }
            else
            {
                double rx = 0;
                if (NumObs != 0)
                    rx = 1.96 / Math.Sqrt(NumObs);
                topY = Math.Max(Math.Abs(minVal), Math.Abs(maxVal));
                if (NumObs != 0)
                    topY = Math.Max(topY, rx);
                topY *= 1.1;
                bottomY = -topY;
                yunits = GetNiceUnitForRange(bottomY, topY, 1.0, false);
            }

            ACF = acf;
            NumObs = nobs;
            Lags = lags;
        }

        private void ACFPlotBox_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                // select from a drop-down menu
                var options = new List<string>();
                options.Add("Copy Values to Clipboard");
                options.Add("Copy Plot to Clipboard");
                options.Add("Export Plot to PDF File");
   
                Point newLocation = PointToScreen(e.Location);
                var m = new DropMenuForm(newLocation, options);
                m.ShowDialog();
                {
                    switch (m.SelectedIndex)
                    {
                        case -1: // no selection
                            break;
                        case 0: // copy values to clipboard
                            CopyValuesToClipboard();
                            break;
                        case 1: // copy values to clipboard
                            CopyPlotToClipboard();
                            break;
                        case 2: // copy values to clipboard
                            ExportPlotToPDF();
                            break;
                    }
                }
            }
        }

        private void CopyValuesToClipboard()
        {
            var sb = new StringBuilder(1024);
            if (Lags != null)
            {
                for (int i = 0; i < Lags.Length; ++i)
                    sb.AppendFormat("{0}\t{1:0.00000}{2}", Lags[i], ACF[i], Environment.NewLine);
            }
            Clipboard.SetText(sb.ToString());
        }

        private void CopyPlotToClipboard()
        {
            // try graphics object from bitmap
            Bitmap bmp = new Bitmap(1200, 850, PixelFormat.Format32bppArgb);
            Graphics g = Graphics.FromImage(bmp);

            CreatePartition(new Rectangle(0, 0, 1200, 850));
            RenderToGraphics(g, 18, 15);
            Clipboard.SetImage(bmp);
        }

        private void ExportPlotToPDF()
        {
            // get file name
            var saveDialog = new SaveFileDialog();
            saveDialog.Filter = "PDF Files (*.pdf)|*.pdf" + "|All Files (*.*)|*.*";

            // use pdfsharp
            if (saveDialog.ShowDialog() == DialogResult.OK)
            {
                PdfDocument document = new PdfDocument(saveDialog.FileName);
                PdfPage page = document.AddPage();
                page.Orientation = PageOrientation.Landscape;
                XGraphics gfx = XGraphics.FromPdfPage(page);
                gfx.ScaleTransform(1.0, 1.0);
                CreatePartition(new Rectangle(0, 0, (int)page.Width, (int)page.Height));
                RenderToXGraphics(gfx, 24, 18);
                document.Close();
            }
        }
    }

}
